#include "syscall.h"

/*monitor variables and shared information
 *setup for dynamic allocation
 */
/*
 *shared data        //
 */

/*pointer to array of ints to represent visitors in the car*/
const int numberOfCars = 3;
const int numberOfLimos = 3;
const int numberOfValets = 2;

int passengers[3] = {1,2,3} ;
int limoPassengers[3] = {3,2,1} ;

/*pointer to array of ints to represent visitors out of the car*/
int outOfCar[3] = {0,0,0} ;
int limoOutOfCar[3] = {0,0,0} ;

/*integer to keep track of number of cars in line*/
int inLine = 0;
int limoLine = 0;

/*integer to keep track of how many people are in line to get the tickets taken*/
int ticketLineCount = 0;
int inMuseum = 0;
int driverWaiting=0;
int limoWaiting = 0;
int onBench = 0;
int working = 2;
int drivercount = 0;
int limodrivercount = 0;
int valetcount = 0;

/*
 *Locks
 */


/*array of lock pointers with one lock for each car based on the index*/
int carLock[3];
int limoLock[3];

/*
 *condition variables
 */
int driverWaitingCV[3];
int visitorExit[3];
int canLeave[3];
int hasKeys[3];
int hasToken[3];
int leaveToken[3];
int readyToLeave[3];
int waitToLeave[3];
int waitExit[3];
int waitCarLeaving[3];
int Tip[3];

/*limo CV's*/
int limoWaitingCV[3];
int visitorLimoExit[3];
int limoCanLeave[3];
int limoHasKeys[3];
int limoHasToken[3];
int limoLeaveToken[3];
int limoReadyToLeave[3];
int limoWaitToLeave[3];
int limoWaitExit[3];
int waitLimoLeaving[3];
int limoTip[3];



int parkingLock;
int lineLock;
int breakLock;

int leaving;
int readyToPark;

int limoLeaving;
int limoReadyToPark;

int waitForCars;
int waitOnCustomers;
int ticketLine;
int managerWaiting;
int backRoom;
int waitForBreak;

int carnumbersArrive;
int carnumbersLeave;
int limoListToPark;
int limoListToLeave;
int infoLock;

/*Driver parameter*/
char name[];
int carNum[3];
int limoNum[3];

/*Valet parameter*/
int currentcar[2];
int myNum[2];

/*Valet Manager parameter*/
int isValetMan = 0; /*0 mean no valet manager, 1 mean there is valet manager*/
int numInBack = 0;
int sum = 0;


/*Visitor parameter*/
int num[12];
int viscarNum[12];
int visCount = 0;

/*for dynamic visitor creation*/
struct visInfo{
  /*char* name;*/
  int carNum;
  int limoNum;
  int limotrue; /*1 means vis on limo, 0 means vis on car*/
  int visNum;
};

struct visInfo info[12];

/*********************************************************/
/*go to museum function***********************************/

void Print(char* str){
  int c = 0;
  while((str[c] != '\n')){
    c++; 
  }
  c++;
  Write(str,c,ConsoleOutput);
	
}
void goToMuseum(){

  int i;
  /*get a random number between 50 and 100*/
  int randomNum = 10;
  /*simulate time inside the museum*/
   for(i = randomNum; i>0; i--){
    Yield();
  }

}


void gettingMuseumLine(int number){

  int carNum1 = number;
 
  Acquire(lineLock);
  /*if no one is in line wake up the ticket taker*/
  if (ticketLineCount == 0){
    Write("Waking up the Ticket Taker\n ",27,ConsoleOutput);
    Signal(lineLock,waitOnCustomers);
  }

  /*increment the in line count*/
  ticketLineCount ++;
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum1);
  Write(" is getting in line for the Ticket Taker\n",41, ConsoleOutput);
  Wait(lineLock,ticketLine); 
  Release(lineLock);
}


void visitorGoingtoMuseum(int number){
   /*get the lock to get in line*/
    Acquire(lineLock);
    /*if no one is in line wake up the ticket taker*/
    if (ticketLineCount == 0){
      Write("Waking up the Ticket Taker\n ",27,ConsoleOutput);
      Signal(lineLock,waitOnCustomers);
  }
    
    /*increment the in line count*/
    ticketLineCount ++;
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(number);
    Write(" is getting in line for the Ticket Taker\n",41, ConsoleOutput);
    Wait(lineLock,ticketLine); 
    Release(lineLock);
    /*Done getting in line for museum*/  


    /*go to the museum*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(number);
    Write(" is entering the museum\n",24,ConsoleOutput);
    goToMuseum();
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(number);
    Write(" is exiting the museum\n",23,ConsoleOutput);
    /*Exiting the museum*/
}
/*
void intCus(visInfo* v){
  v->visNum = visCount;
  visCount++;
}
*/

void Visitor(){
  int i;
  /* visInfo info;
  intCus(&info);

  i = info[i].visNum;
  */
 
  Acquire(infoLock);
  i= visCount;
  visCount++;
  Release(infoLock);
  /*set the number for this visitor*/

  if(info[i].limotrue == 0){
    /*code to check for exit*/
    Acquire(carLock[info[i].carNum]);
    /*make visitor wait to exit the car*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is waiting to exit Car ",24,ConsoleOutput);
    PrintInt(info[i].carNum);
    Write("\n",1,ConsoleOutput);
    Wait(carLock[info[i].carNum],visitorExit[info[i].carNum]);
    /*release the lock*/
    Release(carLock[info[i].carNum]);
  

    /*exiting the car*/
    Acquire(carLock[info[i].carNum]);
    /*print message so you know its happening*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is exiting the car\n",20,ConsoleOutput);
    /*decrement the passengers in the car*/
    passengers[info[i].carNum] --;
    PrintInt(passengers[info[i].carNum]);
    /*increment passengers out of the car*/
    outOfCar[info[i].carNum] ++;
    
    if(passengers[info[i].carNum] == 0){
      /*this means car is empty*/
      /*signal the driver to tell them car is empty*/
      Write("All passengers have exited Car ",26,ConsoleOutput);
      PrintInt(info[i].carNum);
      Write("\n",1,ConsoleOutput);
      Signal(carLock[info[i].carNum],driverWaitingCV[info[i].carNum]);
    }
    /*exit the monitor*/
    Release(carLock[info[i].carNum]);
    /*Done exiting the car */


    /*The passenger can now going to the museum*/
    visitorGoingtoMuseum(i);
    Print("CAR VISITOR VISITED MUSEUM\n");

    /*getting back to the car*/
    Acquire(carLock[info[i].carNum]);    
    /*decrement here so the last will know they are the last*/
    outOfCar[info[i].carNum] --;
    passengers[info[i].carNum] ++;    
    /*checking to see how many people are waiting for a car*/
    if (outOfCar[info[i].carNum] > 0){
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Print(" is waiting for everyone to leave the Museum~~~~~~~~~\n");
      Wait(carLock[info[i].carNum],waitToLeave[info[i].carNum]);
    }else{
      /*if everyone is out of the museum tell the driver*/
      Write("All Visitors from car ",22,ConsoleOutput);
      PrintInt(info[i].carNum);
      Print(" are back****************\n");
      Signal(carLock[info[i].carNum],readyToLeave[info[i].carNum]);
      Wait(carLock[info[i].carNum],waitToLeave[info[i].carNum]);
    }
    /*decrement ahead so that the last passenger will know they are the last*/
    passengers[info[i].carNum] --;
    /*check if all the passengers are in the car*/
    if(passengers[info[i].carNum] > 0){
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Write(" is getting in Car ",22,ConsoleOutput);
      PrintInt(info[i].carNum);
      Write("\n",1,ConsoleOutput);
    }else{
      /*if all passengers are in the car print message and tell driver*/
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Write(" is getting in Car ",17,ConsoleOutput);
      PrintInt(info[i].carNum);
      Write("\n",1,ConsoleOutput);
      Write("All Visitors are in Car ",24,ConsoleOutput);
      PrintInt(info[i].carNum);
      Write("\n",1,ConsoleOutput);
      Signal(carLock[info[i].carNum],readyToLeave[info[i].carNum]);
    }
    /*wait for driver to drive off*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is waiting for Car ",20,ConsoleOutput);
    PrintInt(info[i].carNum);
    Write(" to drive off\n",14,ConsoleOutput);
    Wait(carLock[info[i].carNum],waitExit[info[i].carNum]);
    /*release the lock*/
    Release(carLock[info[i].carNum]);

  }


  /* Limo Visitor Code */
  else if(info[i].limotrue == 1){ 
    /*if the passenger in the limo*/
    /*code to check for exit*/
    Acquire(limoLock[info[i].limoNum]);
    /*make visitor wait to exit the car*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is waiting to exit Limo ",25,ConsoleOutput);
    PrintInt(info[i].limoNum);
    Write("\n",1,ConsoleOutput);
    Wait(limoLock[info[i].limoNum],visitorLimoExit[info[i].limoNum]);
    /*release the lock*/
    Release(limoLock[info[i].limoNum]);


    /*exiting the limo*/
    Acquire(limoLock[info[i].limoNum]);
    /*print message so you know it's happening*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is exiting the limo\n",21,ConsoleOutput);
    /*decrement the passengers in the limo*/
    limoPassengers[info[i].limoNum] --;
    PrintInt(limoPassengers[info[i].limoNum]);
    /*increment passengers out of the car*/
    limoOutOfCar[info[i].limoNum] ++;
    
    if(limoPassengers[info[i].limoNum] == 0){
      /*this means car is empty*/
      /*signal the driver to tell them car is empty*/
      Write("All passengers have exited Limo ",32,ConsoleOutput);
      PrintInt(info[i].limoNum);
      Write("\n",1,ConsoleOutput);
      Signal(limoLock[info[i].limoNum],limoWaitingCV[info[i].limoNum]);
    }
    /*exit the monitor*/
    Release(limoLock[info[i].limoNum]);
    /*Done exiting the car */

    /*the visitor now can go to visit the museum*/
    visitorGoingtoMuseum(i);

    /*getting back to the car*/
    Acquire(limoLock[info[i].limoNum]);    
    /*decrement here so the last will know they are the last*/
    limoOutOfCar[info[i].limoNum] --;
    limoPassengers[info[i].limoNum] ++;    
    /*checking to see how many people are waiting for a car*/
    if (limoOutOfCar[info[i].limoNum] > 0){
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Write(" is waiting for everyone to leave the Museum\n",45,ConsoleOutput);
      Wait(limoLock[info[i].limoNum],limoWaitToLeave[info[i].limoNum]);
    }else{
      /*if everyone is out of the museum tell the driver*/
      Write("All Visitors from limo ",23,ConsoleOutput);
      PrintInt(info[i].limoNum);
      Write(" are back\n",11,ConsoleOutput);
      Signal(limoLock[info[i].limoNum],limoReadyToLeave[info[i].limoNum]);
      Wait(limoLock[info[i].limoNum],limoWaitToLeave[info[i].limoNum]);
    }
    /*decrement ahead so that the last passenger will know they are the last*/
    limoPassengers[info[i].limoNum] --;
    /*check if all the passengers are in the car*/
    if(limoPassengers[info[i].limoNum] > 0){
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Write(" is getting in Limo ",23,ConsoleOutput);
      PrintInt(info[i].limoNum);
      Write("\n",1,ConsoleOutput);
    }else{
      /*if all passengers are in the car print message and tell driver*/
      Write("Visitor ",8,ConsoleOutput);
      PrintInt(i);
      Write(" is getting in Limo ",18,ConsoleOutput);
      PrintInt(info[i].limoNum);
      Write("\n",1,ConsoleOutput);
      Write("All Visitors are in Limo ",25,ConsoleOutput);
      PrintInt(info[i].limoNum);
      Write("\n",1,ConsoleOutput);
      Signal(limoLock[info[i].limoNum],limoReadyToLeave[info[i].limoNum]);
    }
    /*wait for driver to drive off*/
    Write("Visitor ",8,ConsoleOutput);
    PrintInt(i);
    Write(" is waiting for Limo ",21,ConsoleOutput);
    PrintInt(info[i].limoNum);
    Write(" to drive off\n",14,ConsoleOutput);
    Wait(limoLock[info[i].limoNum],limoWaitExit[info[i].limoNum]);
    /*release the lock*/
    Release(limoLock[info[i].limoNum]);

  }






  Exit(0);
}



/********************************************************
 * Driver Code******************************************
 ********************************************************/

/*Function Car Arrive to the Museum*/
void driveInMuseum(int number){
  /* name[] = "Car";*/
  int carNum1 = number;

  Acquire(parkingLock);

  /*code for arriving at museum and getting in line
   *print message to show they have arrived*/
  Write("Car ", 4, ConsoleOutput);
  PrintInt(carNum1);
  Write (" has arrived at the Museum\n", 27, ConsoleOutput);

  /*atomic operation
   *get parking lock*/

  Write("Car ", 4, ConsoleOutput);
  PrintInt(carNum1);
  Write (" is getting in line to be parked\n", 33, ConsoleOutput);  


  /*increment inLine count*/
  inLine++;
  AddtoList(carNum1,carnumbersArrive);

  Write("Car ", 4, ConsoleOutput);
  PrintInt(carNum1);
  Write (" is in line to be parked\n", 25, ConsoleOutput);  

  Signal(parkingLock,waitForCars);
  Wait(parkingLock,readyToPark);
  Release(parkingLock);

}

void limoDriveInMuseum(int number){
 
  int carNum1 = number;

  Acquire(parkingLock);
  /*code for arriving at museum and getting in line
   *print message to show they have arrived
   */

  Write("Limo ", 5, ConsoleOutput);
  PrintInt(carNum1);
  Write (" has arrived at the Museum\n", 27, ConsoleOutput);  

  /*atomic operation
   *get parking lock
   */

  /*print message to get in line*/
  
  Write("Limo ", 5, ConsoleOutput);
  PrintInt(carNum1);
  Write (" is getting in line to be parked\n",33 , ConsoleOutput); 

  /*increment inLine count*/
  limoLine++;
  AddtoList(carNum1,limoListToPark);
  Write("Limo ", 5, ConsoleOutput);
  PrintInt(carNum1);
  Write (" is in line to be parked\n", 26, ConsoleOutput); 

  
  /*wait for condition variable*/
  Signal(parkingLock,waitForCars);
  Wait(parkingLock,limoReadyToPark);
  Release(parkingLock);
}

void removingLimoPassengers(int number){

  int limoNum1 = number;

  /*atomic operation
   *get lock to deal with people in car
   */
  Acquire(limoLock[limoNum1]);
  /*driver meets valet and tells visitors to exit.*/
  Write("Visitors from Limo ", 19, ConsoleOutput);
  PrintInt(limoNum1);
  Write (" can now exit the Limo\n", 23, ConsoleOutput); 

  Broadcast(limoLock[limoNum1],visitorLimoExit[limoNum1]);
  Release(limoLock[limoNum1]);

  /*code for exiting the car
   *enter the car monitor
   */  
  Acquire(limoLock[limoNum1]);
  /*check if all passengers have exited the car*/
  if (limoPassengers[limoNum1] > 0){
    /*this means passengers are still in the car
     *make driver wait for the condition variable
     */
    Write("Limo Driver ", 12, ConsoleOutput);
    PrintInt(limoNum1);
    Write (" is waiting for passengers to exit\n", 35, ConsoleOutput); 

    Wait(limoLock[limoNum1], limoWaitingCV[limoNum1]);
    Write("Limo Driver ", 12, ConsoleOutput);
    PrintInt(limoNum1);
    Write (" is exiting the limo\n",21,ConsoleOutput);
  } else{
    /*all passengers have exited*/
   
    Write("Limo Driver ",12,ConsoleOutput);
    PrintInt(limoNum1);
    Write (" is exiting the limo\n", 21, ConsoleOutput);    
  }
  
  /*exit the monitor*/
  Release(limoLock[limoNum1]);
}

/* Removing passengers from the cars*/
void removingPassengers(int number){
  int carNum1 = number;

  /*atomic operation
   *get lock to deal with people in car
  */
  Acquire(carLock[carNum1]);

  /*driver meets valet and tells visitors to exit.*/

  Write("Visitors from car ", 18, ConsoleOutput);
  PrintInt(carNum1);
  Write (" can now exit the Car\n", 22, ConsoleOutput); 

  Broadcast(carLock[carNum1],visitorExit[carNum1]);
  Release(carLock[carNum1]);

  /*code for exiting the car*/
  Acquire(carLock[carNum1]);
  
  /*check if all passengers have exited the car*/
  if (passengers[carNum1] > 0){
    /*this means passengers are still in the car
     *make driver wait for the condition variable
     */
    Write("Driver ", 7, ConsoleOutput);
    PrintInt(carNum1);
    Write (" is waiting for passengers to exit\n", 35, ConsoleOutput);
    Wait(carLock[carNum1],driverWaitingCV[carNum1]);
    
  } else{
    /*all passengers have exited*/
    Write("Driver ", 7, ConsoleOutput);
    PrintInt(carNum1);
    Write (" is exiting the car\n", 20, ConsoleOutput); 
  }
  
  /*exit the monitor*/
  Release(carLock[carNum1]);
}

/*code for the getting the Parking Token*/
void gettingParkingToken(int number){
 
  int carNum1 = number;
 
  /*getting the lock to enter atomic operation*/
  Acquire(carLock[carNum1]);
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum1);
  Write(" hands over the keys to the Valet\n",34,ConsoleOutput);

  Signal(carLock[carNum1],hasKeys[carNum1]);

  /*wait for a parking token from the valet*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum1);
  Write(" is waiting for the parking token\n",36,ConsoleOutput);
  Wait(carLock[carNum1],hasToken[carNum1]);

  /*message saying they recieved the token*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum1);
  Write(" has received a parking token\n",30,ConsoleOutput);

  /*release the lock*/
  Release(carLock[carNum1]);
}

void gettingLimoParkingToken(int number){

  int carNum1 = number;
 
  /*getting the lock to enter atomic operation*/
  Acquire(limoLock[carNum1]);
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum1);
  Write(" hands over the keys to the Valet\n",34,ConsoleOutput);

  Signal(limoLock[carNum1],limoHasKeys[carNum1]);

  /*wait for a parking token from the valet*/
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum1);
  Write(" is waiting for the parking token\n",34,ConsoleOutput);
  Wait(limoLock[carNum1],limoHasToken[carNum1]);

  /*message saying they recieved the token*/
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum1);
  Write(" has received a parking token\n",30,ConsoleOutput);

  /*release the lock*/
  Release(limoLock[carNum1]);
}



/*************************
 *Driver Thread 
 */

void Driver(){ 

  int i ;


  Acquire(infoLock);
  i= drivercount;
  carNum[i] = drivercount;
  drivercount++;
  Release(infoLock);


  /*car arrive at the museum*/
  driveInMuseum(carNum[i]);

  /*removing people from the car*/
  removingPassengers(carNum[i]);

  /*getting parking token from the valet*/
  gettingParkingToken(carNum[i]);

  /*getting museum line*/
  gettingMuseumLine(carNum[i]);

  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" is entering the museum\n");
  Print("\n");
  inMuseum ++;
  Print("Driver is IN MUSEUM\n");
  goToMuseum();
 

  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" is exiting the museum(^_^)\n");

  /*get the lock to wait for visitor to leave the museum
   *wait for everyone to exit the museum
   *  if driver is alone he will not get onto the leaving CV*/
  Acquire(carLock[carNum[i]]);
  if (outOfCar[carNum[i]] > 0){
    Write("Driver ",7, ConsoleOutput);
    PrintInt(carNum[i]);
    Print(" is waiting for everyone to exit\n");
    Wait(carLock[carNum[i]],readyToLeave[carNum[i]]);
  }
  Release(carLock[carNum[i]]);


  /*tell the valet they want to leave
   *get in line to get a valet so the car can leave
   */  
  Acquire(parkingLock);
  driverWaiting ++;
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" calls the Valet\n");
  Signal(parkingLock,waitForCars);

  /*wait for the valet to come and help them*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum[i]);
  Write(" is waiting for a valet\n",24,ConsoleOutput);
  AddtoList(carNum[i],carnumbersLeave);
  Wait(parkingLock,leaving);
  Release(parkingLock);


  /*give parking token to the valet to get the car back*/
  Acquire(carLock[carNum[i]]);
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" gives his parking token to Valet\n");
  Signal(carLock[carNum[i]],leaveToken[carNum[i]]);
 
 /*wait for the valet to return with the car*/
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" is waiting for his car\n");
  Wait(carLock[carNum[i]],waitCarLeaving[carNum[i]]);

  /*tip the valet*/
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" tips the Valet\n");
  Signal(carLock[carNum[i]],Tip[carNum[i]]);

  /*wait for acknowledgement of tip from valet*/
  Wait(carLock[carNum[i]],canLeave[carNum[i]]);
 
  /*tell all visitors they can get in the car*/
  Write("Everyone from car ",18,ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" can get in the Car\n");
  Broadcast(carLock[carNum[i]],waitToLeave[carNum[i]]);

  /*check if driver did not have any passengers*/
  if(passengers[carNum[i]] > 0){
    /*if driver did have passengers wait for all of them
     *to get back in the car*/
    Write("Driver ",7,ConsoleOutput);
    PrintInt(carNum[i]);
    Print(" is waiting for everyone to get in\n");
    Wait(carLock[carNum[i]],readyToLeave[carNum[i]]);
  }    

  /*tell all visitors they are leaving the museum*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum[i]);
  Print(" gets into the Car and leaves Museum!YEAH!\n");
  Broadcast(carLock[carNum[i]],waitExit[carNum[i]]);

  Release(carLock[carNum[i]]);
  
  Exit(0);


}



void LimoDriver(){

  int i;
  Acquire(infoLock);
  i = limodrivercount;
  limoNum[i]=limodrivercount;
  limodrivercount++;
  Release(infoLock);

  /*Limo drive to the museum*/
  limoDriveInMuseum(limoNum[i]); 

  removingLimoPassengers(limoNum[i]);

  gettingLimoParkingToken(limoNum[i]);

  /* wait for visitors to return from museum */
  Acquire(limoLock[limoNum[i]]);
  
  if (limoOutOfCar[limoNum[i]] > 0){
    Write("limo Driver ",12, ConsoleOutput);
    PrintInt(limoNum[i]);
    Print(" is waiting for everyone to exit\n");
     
    Wait(limoLock[limoNum[i]],limoReadyToLeave[limoNum[i]]);
  }
  else
    Print("I'm still waiting for visitors\n");
  Release(limoLock[limoNum[i]]);


  /*Everybody back to the limo tell the valet they want to leave*/
  Acquire(parkingLock);
  limoWaiting ++;
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Print(" calls the Valet\n");
  Signal(parkingLock,waitForCars);
  /*wait for the valet to come and help them*/
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Write(" is waiting for a Valet\n",24,ConsoleOutput);
  AddtoList(limoNum[i],limoListToLeave);
  Wait(parkingLock,limoLeaving); 
  Release(parkingLock);

  Acquire(limoLock[limoNum[i]]);
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Print(" gives his parking token to Valet\n");
  Signal(limoLock[limoNum[i]],limoLeaveToken[limoNum[i]]);
  
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Write(" is waiting for his Limo\n",22,ConsoleOutput);
  Wait(limoLock[limoNum[i]],waitLimoLeaving[limoNum[i]]);
  Release(limoNum[i]);


  /*tip the valet to get the limo back*/
  Acquire(limoLock[limoNum[i]]);
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Write(" tips the Valet\n",14,ConsoleOutput);
  Signal(limoLock[limoNum[i]],limoTip[limoNum[i]]);
  /*wait for acknowledgement of tip from valet*/
  Wait(limoLock[limoNum[i]],limoCanLeave[limoNum[i]]);

  /*tell all visitors they can get in the car*/
  Write("Everyone from Limo ",19,ConsoleOutput);
  PrintInt(limoNum[i]);
  Print(" can get in the Limo\n");
  Broadcast(limoLock[limoNum[i]],limoWaitToLeave[limoNum[i]]);

  /*check if driver did not have any passengers*/
  if(limoPassengers[limoNum[i]] > 0){
    /*if driver did have passengers wait for all of them
     *to get back in the car*/
    Write("Limo Driver ",12,ConsoleOutput);
    PrintInt(limoNum[i]);
    Print(" is waiting for everyone to get in\n");
    Wait(limoLock[limoNum[i]],limoReadyToLeave[limoNum[i]]);
  }    

  /*tell all visitors they are leaving the museum*/
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(limoNum[i]);
  Print(" gets into the Limo and leaves Museum!YEAH!\n");
  Broadcast(limoLock[limoNum[i]],limoWaitExit[limoNum[i]]);
  Release(limoLock[limoNum[i]]);

  Exit(0);
   

}

/**********************************
 *********************************
 **** VALET **********************/
/*function for valet to park a car*/
void parkCar(int currentcar0, int myNum0){
  int i;

  /*atomic operation to approach the car*/
  Acquire(parkingLock);
  /*set the car you are working with*/
  currentcar0 = (int)RemovefromList(carnumbersArrive);

  /*Tell the driver they are there to help them*/
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" has approached Car ",20,ConsoleOutput);
  PrintInt(currentcar0);
  Write("\n",1,ConsoleOutput);

  Signal(parkingLock,readyToPark);
  /*decrement the number of cars in line to be parked*/
  inLine --;
  /*release the lock*/
  Release(parkingLock);


  /*get the current car's lock and exchange parking token*/
  Acquire(carLock[currentcar0]);
  /*wait for the keys from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" is waiting for Driver ",24, ConsoleOutput);
  PrintInt(currentcar0);
  Write("'s keys\n", 8, ConsoleOutput);
  Wait(carLock[currentcar0],hasKeys[currentcar0]);
  /*message saying they recieved the keys*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" has received the keys and hands over a parking token\n",54, ConsoleOutput);
  Signal(carLock[currentcar0],hasToken[currentcar0]);
  /*go and park the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" is parking the car\n",20, ConsoleOutput);
   /*get a random number between 5 and 20 to park the car*/
  for(i = 15; i>0; i--){
    Yield();
  }  
  Write("Car ",4, ConsoleOutput);
  PrintInt(currentcar0);
  Write(" has been parked\n",17, ConsoleOutput);
 
  /*release the lock*/
  Release(carLock[currentcar0]);
  /*reset current car so it doesnt mess up other cars*/
  currentcar0 = -1;
}

/*code for parking the limo*/
void parkLimo(int currentcar0, int myNum0){
  int i;
  /*atomic operation*/
  Acquire(parkingLock);
  /*set the car you are working with*/
  currentcar0 = (int)RemovefromList(limoListToPark);
  /*Tell the driver they are there to help them*/
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" has approached Limo ",21,ConsoleOutput);
  PrintInt(currentcar0);
  Write("\n",1,ConsoleOutput);
  Signal(parkingLock,limoReadyToPark);
  /*decrement the number of cars in line to be parked*/
  limoLine --;
  /*release the lock*/
  Release(parkingLock);


  /*get the current car's lock to exchange the token*/
  Acquire(limoLock[currentcar0]);
  /*wait for the keys from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" is waiting for Limo Driver's Keys\n",35, ConsoleOutput);
  Wait(limoLock[currentcar0],limoHasKeys[currentcar0]);
  /*message saying they recieved the keys*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" has received the keys and hands over a parking token for Limo Driver\n",70, ConsoleOutput);
  Signal(limoLock[currentcar0],limoHasToken[currentcar0]);
  /*go and park the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" is parking the Limo\n",21, ConsoleOutput);
  
  Release(limoLock[currentcar0]);

  /*get a random number between 5 and 20 to generate the time to park limo*/
  for(i = 20; i>0; i--){
    Yield();
  }
  Write("Limo ",5, ConsoleOutput);
  PrintInt(currentcar0);
  Write(" has been parked\n",17, ConsoleOutput);



  /*reset current car so it doesnt mess up other cars*/
  currentcar0 = -1;
}

void retrieveLimo(int currentcar0, int myNum0){
  int randomNum = 20;
  int i;

  /*enter atomic operation to retrieve the limo*/
  Acquire(parkingLock);
  /*set the car the valet is working with*/
  currentcar0 = (int)RemovefromList(limoListToLeave);
  /*decrement the driver waiting to leave coutnt*/
  limoWaiting --;
  /*tells the driver they are there to help them*/
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" has approached Limo ",21,ConsoleOutput);
  PrintInt(currentcar0);
  Write(" and gets his Token\n",21,ConsoleOutput);
  Signal(parkingLock,limoLeaving);
  Release(parkingLock);

  /*get the current car's lock*/
  Acquire(limoLock[currentcar0]);
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" is getting Limo ",17,ConsoleOutput);
  PrintInt(currentcar0);
  Write("\n",1,ConsoleOutput);  
  Release(limoLock[currentcar0]);
  /*simulate time to get the car*/
  for(i = randomNum; i>0; i--){
    Yield();
  }
  /*  Release(limoLock[currentcar0]);*/

  /*drive back the car to get the tips*/
  Acquire(limoLock[currentcar0]);
  /*tell the driver they have returned with the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" has returned with Limo",24, ConsoleOutput);
  PrintInt(currentcar0);
  Write("\n",1,ConsoleOutput);
  Signal(limoLock[currentcar0],waitLimoLeaving[currentcar0]);
  
  /*wait for a tip from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Print(" is waiting for his tip\n");
  Wait(limoLock[currentcar0],limoTip[currentcar0]);

  /*message that they recieved the tip*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Write(" has received for his tip\n",26, ConsoleOutput);

  /*tell the driver that they can get in the car and leave*/
  Write("Limo ",5, ConsoleOutput);
  PrintInt(currentcar0);
  Write(" can get ready to leave\n",20, ConsoleOutput);
  Signal(limoLock[currentcar0],limoCanLeave[currentcar0]);
  Release(limoLock[currentcar0]);

  /*reset current car so it doesnt mess up other cars*/
  currentcar0 = -1;
}

/*function for a valet to retrieve a car*/
void retrieveCar(int currentcar0, int myNum0){
  int i; 
  /*atomic operation to identify the car*/
  Acquire(parkingLock);
  /*set the car the valet is working with*/
  currentcar0 = (int)RemovefromList(carnumbersLeave);
  /*decrement the driver waiting to leave coutnt*/
  driverWaiting --;
  /*tells the driver they are there to help them*/
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" has approached Car ",20,ConsoleOutput);
  PrintInt(currentcar0);
  Write(" and gets his Token\n",21,ConsoleOutput);
  Signal(parkingLock,leaving);
  Release(parkingLock);


  /*get the current car's lock*/
  Acquire(carLock[currentcar0]);
  /*get the car from the parking lot*/
  Write("Valet ",6,ConsoleOutput);
  PrintInt(myNum0);
  Write(" is getting Car ",14,ConsoleOutput);
  PrintInt(currentcar0);
  Write("\n",1,ConsoleOutput);  
  Release(carLock[currentcar0]);


  /*get a random number between 5 and 20 to get the car*/
  for(i = 10; i>0; i--){
    Yield();
  }


  Acquire(carLock[currentcar0]);
  /*tell the driver they have returned with the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Print(" has returned with Car\n");
  Signal(carLock[currentcar0],waitCarLeaving[currentcar0]);

  /*wait for a tip from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Print("is waiting for his tip\n");
  Wait(carLock[currentcar0],Tip[currentcar0]);
  /*message that they recieved the tip*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum0);
  Print(" has received for his tip\n");
 
  /*tell the driver that they can get in the car and leave*/
  Write("Car ",4, ConsoleOutput);
  PrintInt(currentcar0);
  Print(" can get ready to leave\n");
  Signal(carLock[currentcar0],canLeave[currentcar0]);
  Release(carLock[currentcar0]);

  /*reset current car so it doesnt mess up other cars*/
  currentcar0 = -1;

}


/**************************************************
 *Main code for Valet *****************************/
void Valet(){
  int i;
  

  Acquire(infoLock);
  i = valetcount;
  myNum[i] = valetcount;
  valetcount++;
  currentcar[i] = -1;
  Release(infoLock);

  /*Write("Valet\n",6,ConsoleOutput);*/


   while(1==1){
     /*  Write("*limo waiting* ",15,ConsoleOutput);    
	 PrintInt(limoWaiting);*/
     if(limoLine>0){
       /*Write("parklimo\n",9,ConsoleOutput);*/
       parkLimo(currentcar[i],myNum[i]);
     }
     else if(limoWaiting != 0){
       Write("retrievelimo\n",13,ConsoleOutput);
       retrieveLimo(currentcar[i],myNum[i]);
     }
     else if(driverWaiting != 0 ){
       retrieveCar(currentcar[i],myNum[i]);
     }
     else if (inLine != 0){
       /* Write("parkcar\n",8,ConsoleOutput);*/
       parkCar(currentcar[i],myNum[i]);
     }
    
   }
   Exit(0);
}


/**************************************************
 * Valet Manager **********************************
 **************************************************/
void sendOnBreak(){
  Signal(breakLock,waitForBreak);
}

void goBackToWork(){
  Signal(breakLock,backRoom);
}

void valetManager(){
  while(1==1){
    Acquire(breakLock);
    /*update the sum value to the newest amount*/
    sum = limoWaiting + limoLine + inLine + driverWaiting;
    if(onBench >= 1){/*if more than one valet is on the bench send one on break*/
      sendOnBreak();
    }
    if (sum >= 4){/*if more than 4 cars are waiting to be handled send a valet back out*/
      goBackToWork();
    }
    Release(breakLock);
    
  }
}


/**************************************************
 *Ticket Taker************************************       
 ************************************************ */
void TicketTaker(){
  while (1 == 1){
    Acquire(lineLock);
    /*check the count to see if people are in line*/
    if (ticketLineCount > 0){
      /*accept the ticket from the first person in line*/
      Write("Ticket accepted**\n",18,ConsoleOutput);
      Signal(lineLock,ticketLine);
      /*decrement the count of people in line*/
      ticketLineCount --;
    }else{
      /*if no one is in line go to sleep*/
      Write("Ticket Taker is waiting for customers\n",39,ConsoleOutput);
      Wait(lineLock,waitOnCustomers);

    }
    Release(lineLock);
  }
  Exit(0);
}

/************************************************
 ************************************************/
/* MAIN FUNCTION ********************************/

int main () {

  int i;

  Write("Start the museum simulation \n",30, ConsoleOutput);
  Write("There are 3 cars, 3 limos   \n",30, ConsoleOutput);
  Write("         2 valets,1 manager \n",30, ConsoleOutput);
  Write("# visitors in cars is [1,2,3],",30, ConsoleOutput);
  Write("# visitors in limos is [3,2,1]\n",31, ConsoleOutput); 

  parkingLock = (int)CreateLock();
  lineLock = (int)CreateLock();  breakLock = (int)CreateLock() ;

  leaving = (int)CreateCondition();
  readyToPark = (int)CreateCondition();
  
  limoLeaving = (int)CreateCondition();
  limoReadyToPark = (int)CreateCondition();
  
  waitForCars = (int)CreateCondition();
  waitOnCustomers = (int)CreateCondition();
  ticketLine = (int)CreateCondition();
  managerWaiting = (int)CreateCondition();
  backRoom = (int)CreateCondition();
  waitForBreak = (int)CreateCondition();
  
  carnumbersArrive = (int)CreateList();
  carnumbersLeave = (int)CreateList();
  limoListToPark = (int)CreateList();
  limoListToLeave = (int)CreateList();

  infoLock = (int)CreateLock();
  

  for (i = 0; i<3; i++) 
    driverWaitingCV[i] = (int)CreateCondition();
  
  for (i = 0; i<3; i++) 
    visitorExit[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    canLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    hasKeys[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    hasToken[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    leaveToken[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    readyToLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    waitToLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    waitExit[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    waitCarLeaving[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    Tip[i] = (int)CreateCondition();

/*limo CV's*/
  
  for (i = 0; i<3; i++) 
    limoWaitingCV[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    visitorLimoExit[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoCanLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoHasKeys[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoHasToken[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoLeaveToken[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoReadyToLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoWaitToLeave[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoWaitExit[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    waitLimoLeaving[i] = (int)CreateCondition();
  for (i = 0; i<3; i++) 
    limoTip[i] = (int)CreateCondition();

  /*initialize locks*/
  for (i = 0; i<3; i++) 
    carLock[i] = (int)CreateLock();
  for (i = 0; i<3; i++) 
    limoLock[i] = (int)CreateLock();  

   for(i=0;i<3;i++){
    Fork (Driver);
    }
  for(i = 0; i<3;i++){
    Fork(LimoDriver);}
    

  
  Fork(TicketTaker);
  Fork(Valet);
  Fork(Valet);

  info[0].carNum = 0;
  info[0].limoNum = -1;
  info[0].limotrue = 0;



  info[1].carNum = 1;
  info[1].limoNum = -1;
  info[1].limotrue = 0;

  info[2].carNum = 1;
  info[2].limoNum = -1;
  info[2].limotrue = 0;

  info[3].carNum = 2;
  info[3].limoNum = -1;
  info[3].limotrue = 0;

  info[4].carNum = 2;
  info[4].limoNum = -1;
  info[4].limotrue = 0;
  
  info[5].carNum = 2;
  info[5].limoNum = -1;
  info[5].limotrue = 0;

  info[6].carNum = -1;
  info[6].limoNum = 0;
  info[6].limotrue = 1;

  info[7].carNum = -1;
  info[7].limoNum = 0;
  info[7].limotrue = 1;

  info[8].carNum = -1;
  info[8].limoNum = 0;
  info[8].limotrue = 1;

  info[9].carNum = -1;
  info[9].limoNum = 1;
  info[9].limotrue = 1;

  info[10].carNum = -1;
  info[10].limoNum = 1;
  info[10].limotrue = 1;

  info[11].carNum = -2;
  info[11].limoNum = 2;
  info[11].limotrue = 1;

  for(i=0;i<12;i++){
    Fork(Visitor);
  }

  
  Exit(0);
}
